class_name ExtCommon
extends Reference

var query: QueryManager
var hp_m: Multi
var data_m: Multi
var ext: Single
var buff_group_m: Multi
var damage_m: Multi
var be_damage_m: Multi

enum DamageType { Crit = 1 << 6 }
const QUERY_LIST = [
	["hp_m", "HpC"],
	["data_m", "DataC"],
	["ext", "Ext"],
	["buff_group_m", "BuffGroupC"],
	["damage_m", "DamageC"],
	["be_damage_m", "BeDamageC"]
]
const REGISTER_FUNCS = ["calc_damage", "damage"]


func _init(world: EcsWorld):
	query = world.query_manager
	var _c = world.connect("world_ready", self, "on_world_ready")

	for func_name in REGISTER_FUNCS:
		var ref = funcref(self, func_name)
		Funcs.reg(func_name, ref)


func on_world_ready():
	for item in QUERY_LIST:
		var multi = query.fetch_data(item[1])
		set(item[0], multi)


#calc (2*f.data.level+10)/250 * v * s.get('power') * f.data.power + 2
func calc_damage(fighter, _target, _buff: Buff, skill: SkillCmdC.Skill, value):
	var fdata = data_m.get(fighter) as DataC
	var level = fdata.level
	var fpower = fdata.power
	var spower = skill.get("power")
	var calc_value = (2 * level + 10) / 250 * value * fpower * spower + 2
	return calc_value


# real damage function
func damage(buff: Buff, target: int, _type: String, value, _bt):
	var skill = buff.skill
	var fdata = data_m.get(buff.fighter) as DataC
	var _tdata = data_m.get(target) as DataC
	var crit_level = skill.get(C.SkillAttrKey.critLevel)
	var crit_rate = fdata.crit_ratio
	var crip_plus = fdata.crit_plus
	var is_crit = EffectUtil.next_int(1, 100) <= crit_rate
	if crit_level == -1:
		is_crit = true
	var damage_value = EffectUtil.get_buff_value(value)
	damage_value = calc_damage(buff.fighter, target, buff, skill, damage_value)
	var damage_type = 0
	if is_crit:
		damage_type |= DamageType.Crit
		damage_value = damage_value * (1 + crip_plus)
	print("%d be damaged from %d value:%d" % [target, buff.fighter, damage_value])
	damage_event(buff, target, damage_type, damage_value)


func damage_event(buff: Buff, target: int, damage_type, damage_value: int):
	var damage = damage_m.get(buff.fighter) as Damage.DamageC
	if not damage:
		damage = Damage.DamageC.new()
		damage_m.insert(buff.fighter, damage)
	damage.buff = buff
	damage.value = damage_value
	damage.type = damage_type
	var be_damage = be_damage_m.get(target) as Damage.BeDamageC
	if not be_damage:
		be_damage = Damage.BeDamageC.new()
		be_damage_m.insert(target, be_damage)
	be_damage.buff = buff
	be_damage.value = damage_value
	be_damage.type = damage_type
	be_damage.fighter = buff.fighter
	#trigger calc_damage event
	damage.action_target = {action = C.DamageActionState.calcDamage, target = target}
	be_damage.action = C.DamageActionState.beCalcDamage

	var fb = buff_group_m.get(buff.fighter) as BuffGroupC
	var tb = buff_group_m.get(target) as BuffGroupC
	if fb:
		BuffUtil.fire_buff(ext.data, buff.fighter, fb, C.DamageActionState.calcDamage)
	if tb:
		BuffUtil.fire_buff(ext.data, target, tb, C.DamageActionState.beCalcDamage)
	var hp = hp_m.get(target) as HpC
	hp.reduce_hp(be_damage.value)
	damage.value = be_damage.value
	damage.action_target = {action = C.DamageActionState.damage, target = target}
	be_damage.action = C.DamageActionState.beDamage

	if fb:
		BuffUtil.fire_buff(ext.data, buff.fighter, fb, C.DamageActionState.damage)
	if tb:
		BuffUtil.fire_buff(ext.data, target, tb, C.DamageActionState.beDamage)
	if hp.value > 0:
		return

	damage.action_target = {action = C.DamageActionState.kill, target = target}
	be_damage.action = C.DamageActionState.dead
	if fb:
		BuffUtil.fire_buff(ext.data, buff.fighter, fb, C.DamageActionState.kill)
	if tb:
		BuffUtil.fire_buff(ext.data, target, tb, C.DamageActionState.dead)
